home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / sc6.8 / part02 < prev    next >
Encoding:
Internet Message Format  |  1990-09-30  |  54.1 KB

  1. Subject:  v23i022:  The SC Spreadsheet, release 6.8, Part02/06
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: ef58239c 06502ec8 315fb6ca e68c7550
  5.  
  6. Submitted-by: Jeff Buhrt <sawmill!buhrt>
  7. Posting-number: Volume 23, Issue 22
  8. Archive-name: sc6.8/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  interp.c sc6.8p1.hdr sres.sed
  17. # Wrapped by rsalz@litchi.bbn.com on Fri Jul 13 15:24:18 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 2 (of 6)."'
  21. if test -f 'interp.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'interp.c'\"
  23. else
  24.   echo shar: Extracting \"'interp.c'\" \(48096 characters\)
  25.   sed "s/^X//" >'interp.c' <<'END_OF_FILE'
  26. X/*    SC    A Spreadsheet Calculator
  27. X *        Expression interpreter and assorted support routines.
  28. X *
  29. X *        original by James Gosling, September 1982
  30. X *        modified by Mark Weiser and Bruce Israel, 
  31. X *            University of Maryland
  32. X *
  33. X *              More mods Robert Bond, 12/86
  34. X *        More mods by Alan Silverstein, 3-4/88, see list of changes.
  35. X *        $Revision: 6.8 $
  36. X */
  37. X
  38. X#define DEBUGDTS 1        /* REMOVE ME */
  39. X/* #define EXPRTREE    /* expr. dependency tree stuff, not ready yet */
  40. X
  41. X#ifdef aiws
  42. X#undef _C_func            /* Fixes for undefined symbols on AIX */
  43. X#endif
  44. X
  45. X#ifdef IEEE_MATH
  46. X#include <ieeefp.h>
  47. X#endif /* IEEE_MATH */
  48. X
  49. X#include <math.h>
  50. X#include <signal.h>
  51. X#include <setjmp.h>
  52. X#include <stdio.h>
  53. X
  54. Xextern int errno;        /* set by math functions */
  55. X#ifdef BSD42
  56. X#include <strings.h>
  57. X#include <sys/time.h>
  58. X#ifndef strchr
  59. X#define strchr index
  60. X#endif
  61. X#else
  62. X#include <time.h>
  63. X#ifndef SYSIII
  64. X#include <string.h>
  65. X#endif
  66. X#endif
  67. X
  68. X#include <curses.h>
  69. X#include "sc.h"
  70. X
  71. X#if defined(BSD42) || defined(BSD43)
  72. Xchar *re_comp();
  73. X#endif
  74. X#if defined(SYSV2) || defined(SYSV3)
  75. Xchar *regcmp();
  76. Xchar *regex();
  77. X#endif
  78. X
  79. X#ifdef SIGVOID
  80. X    void quit();
  81. X#else
  82. X    int quit();
  83. X#endif
  84. X
  85. X/* Use this structure to save the the last 'g' command */
  86. X
  87. Xstruct go_save {
  88. X    int g_type;
  89. X    double g_n;
  90. X    char *g_s;
  91. X    int  g_row;
  92. X    int  g_col;
  93. X} gs;
  94. X
  95. X/* g_type can be: */
  96. X
  97. X#define G_NONE 0            /* Starting value - must be 0*/
  98. X#define G_NUM 1
  99. X#define G_STR 2
  100. X#define G_CELL 3
  101. X
  102. X#define ISVALID(r,c)    ((r)>=0 && (r)<maxrows && (c)>=0 && (c)<maxcols)
  103. X
  104. Xextern FILE *popen();
  105. X
  106. Xjmp_buf fpe_save;
  107. Xint    exprerr;    /* Set by eval() and seval() if expression errors */
  108. Xdouble  prescale = 1.0;    /* Prescale for constants in let() */
  109. Xint    extfunc  = 0;    /* Enable/disable external functions */
  110. Xint     loading = 0;    /* Set when readfile() is active */
  111. Xdouble fn1_eval();
  112. Xdouble fn2_eval();
  113. Xstruct    ent *firstev = (struct ent *)0;    /* first expr in the eval list */
  114. X
  115. X#define PI (double)3.14159265358979323846
  116. X#define dtr(x) ((x)*(PI/(double)180.0))
  117. X#define rtd(x) ((x)*(180.0/(double)PI))
  118. X
  119. Xdouble finfunc(fun,v1,v2,v3)
  120. Xint fun;
  121. Xdouble v1,v2,v3;
  122. X{
  123. X     double answer,p;
  124. X     p = fn2_eval(pow, 1 + v2, v3);
  125. X     switch(fun)
  126. X     {
  127. X     case PV:
  128. X         answer = v1 * (1 - 1/p) / v2;
  129. X         break;
  130. X     case FV:
  131. X         answer = v1 * (p - 1) / v2;
  132. X         break;
  133. X     case PMT:
  134. X         answer = v1 * v2 / (1 - 1/p);
  135. X         break;
  136. X    default:
  137. X        error("Unknown function in finfunc");
  138. X        return((double)0);
  139. X    }
  140. X    return(answer);
  141. X}
  142. X
  143. Xchar *
  144. Xdostindex( val, minr, minc, maxr, maxc)
  145. Xdouble val;
  146. Xint minr, minc, maxr, maxc;
  147. X{
  148. X    register r,c;
  149. X    register struct ent *p;
  150. X    char *pr;
  151. X    int x;
  152. X
  153. X    x = (int) val;
  154. X    r = minr; c = minc;
  155. X    p = (struct ent *)0;
  156. X    if ( minr == maxr ) { /* look along the row */
  157. X    c = minc + x - 1;
  158. X    if (c <= maxc && c >=minc)
  159. X        p = *ATBL(tbl, r, c);
  160. X    } else if ( minc == maxc ) { /* look down the column */
  161. X    r = minr + x - 1;
  162. X    if (r <= maxr && r >=minr)
  163. X        p = *ATBL(tbl, r, c);
  164. X    } else {
  165. X    error ("range specified to @stindex");
  166. X    return((char *)0);
  167. X    }
  168. X
  169. X    if (p && p->label) {
  170. X    pr = xmalloc((unsigned)(strlen(p->label)+1));
  171. X    (void)strcpy(pr, p->label);
  172. X    return (pr);
  173. X     } else
  174. X    return((char *)0);
  175. X}
  176. X
  177. Xdouble
  178. Xdoindex( val, minr, minc, maxr, maxc)
  179. Xdouble val;
  180. Xint minr, minc, maxr, maxc;
  181. X{
  182. X    double v;
  183. X    register r,c;
  184. X    register struct ent *p;
  185. X    int x;
  186. X
  187. X    x = (int) val;
  188. X    v = (double)0;
  189. X    r = minr; c = minc;
  190. X    if ( minr == maxr ) { /* look along the row */
  191. X    c = minc + x - 1;
  192. X    if (c <= maxc && c >=minc 
  193. X        && (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
  194. X                    return p->v;
  195. X    }
  196. X    else if ( minc == maxc ){ /* look down the column */
  197. X    r = minr + x - 1;
  198. X    if (r <= maxr && r >=minr 
  199. X        && (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
  200. X                    return p->v;
  201. X    }
  202. X    else error(" range specified to @index");
  203. X    return v;
  204. X}
  205. X
  206. Xdouble
  207. Xdolookup( val, minr, minc, maxr, maxc, offr, offc)
  208. Xstruct enode * val;
  209. Xint minr, minc, maxr, maxc, offr, offc;
  210. X{
  211. X    double v, ret = (double)0;
  212. X    register r,c;
  213. X    register struct ent *p = (struct ent *)0;
  214. X    int incr,incc,fndr,fndc;
  215. X    char *s;
  216. X
  217. X    incr = (offc != 0); incc = (offr != 0);
  218. X    if (etype(val) == NUM) {
  219. X    v = eval(val);
  220. X    for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
  221. X        if ( (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) {
  222. X        if (p->v <= v) {
  223. X            fndr = incc ? (minr + offr) : r;
  224. X            fndc = incr ? (minc + offc) : c;
  225. X            if (ISVALID(fndr,fndc))
  226. X            p = *ATBL(tbl, fndr, fndc);
  227. X            else error(" range specified to @[hv]lookup");
  228. X            if ( p && p->flags&is_valid)
  229. X            ret = p->v;
  230. X        } else break;
  231. X        }
  232. X    }
  233. X    } else {
  234. X    s = seval(val);
  235. X    for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
  236. X        if ( (p = *ATBL(tbl, r, c)) && p->label ) {
  237. X        if (strcmp(p->label,s) == 0) {
  238. X            fndr = incc ? (minr + offr) : r;
  239. X            fndc = incr ? (minc + offc) : c;
  240. X            if (ISVALID(fndr,fndc))
  241. X            p = *ATBL(tbl, fndr, fndc);
  242. X            else error(" range specified to @[hv]lookup");
  243. X            break;
  244. X        }
  245. X        }
  246. X    }
  247. X    if ( p && p->flags&is_valid)
  248. X        ret = p->v;
  249. X    xfree(s);
  250. X    }
  251. X    return ret;
  252. X}
  253. X
  254. Xdouble
  255. Xdocount(minr, minc, maxr, maxc)
  256. Xint minr, minc, maxr, maxc;
  257. X{
  258. X    int v;
  259. X    register r,c;
  260. X    register struct ent *p;
  261. X
  262. X    v = 0;
  263. X    for (r = minr; r<=maxr; r++)
  264. X    for (c = minc; c<=maxc; c++)
  265. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
  266. X        v++;
  267. X    return v;
  268. X}
  269. X
  270. Xdouble
  271. Xdosum(minr, minc, maxr, maxc)
  272. Xint minr, minc, maxr, maxc;
  273. X{
  274. X    double v;
  275. X    register r,c;
  276. X    register struct ent *p;
  277. X
  278. X    v = (double)0;
  279. X    for (r = minr; r<=maxr; r++)
  280. X    for (c = minc; c<=maxc; c++)
  281. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
  282. X        v += p->v;
  283. X    return v;
  284. X}
  285. X
  286. Xdouble
  287. Xdoprod(minr, minc, maxr, maxc)
  288. Xint minr, minc, maxr, maxc;
  289. X{
  290. X    double v;
  291. X    register r,c;
  292. X    register struct ent *p;
  293. X
  294. X    v = 1;
  295. X    for (r = minr; r<=maxr; r++)
  296. X    for (c = minc; c<=maxc; c++)
  297. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
  298. X        v *= p->v;
  299. X    return v;
  300. X}
  301. X
  302. Xdouble
  303. Xdoavg(minr, minc, maxr, maxc)
  304. Xint minr, minc, maxr, maxc;
  305. X{
  306. X    double v;
  307. X    register r,c,count;
  308. X    register struct ent *p;
  309. X
  310. X    v = (double)0;
  311. X    count = 0;
  312. X    for (r = minr; r<=maxr; r++)
  313. X    for (c = minc; c<=maxc; c++)
  314. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  315. X        v += p->v;
  316. X        count++;
  317. X        }
  318. X
  319. X    if (count == 0) 
  320. X    return ((double) 0);
  321. X
  322. X    return (v / (double)count);
  323. X}
  324. X
  325. Xdouble
  326. Xdostddev(minr, minc, maxr, maxc)
  327. Xint minr, minc, maxr, maxc;
  328. X{
  329. X    double lp, rp, v, nd;
  330. X    register r,c,n;
  331. X    register struct ent *p;
  332. X
  333. X    n = 0;
  334. X    lp = 0;
  335. X    rp = 0;
  336. X    for (r = minr; r<=maxr; r++)
  337. X    for (c = minc; c<=maxc; c++)
  338. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  339. X        v = p->v;
  340. X        lp += v*v;
  341. X        rp += v;
  342. X        n++;
  343. X        }
  344. X
  345. X    if ((n == 0) || (n == 1)) 
  346. X    return ((double) 0);
  347. X    nd = (double)n;
  348. X    return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
  349. X}
  350. X
  351. Xdouble
  352. Xdomax(minr, minc, maxr, maxc)
  353. Xint minr, minc, maxr, maxc;
  354. X{
  355. X    double v = (double)0;
  356. X    register r,c,count;
  357. X    register struct ent *p;
  358. X
  359. X    count = 0;
  360. X    for (r = minr; r<=maxr; r++)
  361. X    for (c = minc; c<=maxc; c++)
  362. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  363. X        if (!count) {
  364. X            v = p->v;
  365. X            count++;
  366. X        } else if (p->v > v)
  367. X            v = p->v;
  368. X        }
  369. X
  370. X    if (count == 0) 
  371. X    return ((double) 0);
  372. X
  373. X    return (v);
  374. X}
  375. X
  376. Xdouble
  377. Xdomin(minr, minc, maxr, maxc)
  378. Xint minr, minc, maxr, maxc;
  379. X{
  380. X    double v = (double)0;
  381. X    register r,c,count;
  382. X    register struct ent *p;
  383. X
  384. X    count = 0;
  385. X    for (r = minr; r<=maxr; r++)
  386. X    for (c = minc; c<=maxc; c++)
  387. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  388. X        if (!count) {
  389. X            v = p->v;
  390. X            count++;
  391. X        } else if (p->v < v)
  392. X            v = p->v;
  393. X        }
  394. X
  395. X    if (count == 0) 
  396. X    return ((double) 0);
  397. X
  398. X    return (v);
  399. X}
  400. X
  401. X#define sec_min 60
  402. X#define sec_hr  3600L
  403. X#define sec_day 86400L
  404. X#define sec_yr  31471200L     /* 364.25 days/yr */
  405. X#define sec_mo  2622600L       /* sec_yr/12: sort of an average */
  406. Xint mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  407. X
  408. Xdouble
  409. Xdodts(mo, day, yr)
  410. Xint mo, day, yr;
  411. X{
  412. X    long trial;
  413. X    register struct tm *tp; 
  414. X    register int i;
  415. X    register long jdate;
  416. X
  417. X    mdays[1] = 28 + (yr%4 == 0);
  418. X
  419. X    if (mo < 1 || mo > 12 || day < 1 || day > mdays[--mo] ||
  420. X        yr > 1999 || yr < 1970) {
  421. X    error("@dts: invalid argument");
  422. X    return(0.0);
  423. X    }
  424. X
  425. X    jdate = day-1;
  426. X    for (i=0; i<mo; i++)
  427. X        jdate += mdays[i];
  428. X    for (i = 1970; i < yr; i++)
  429. X        jdate += 365 + (i%4 == 0);
  430. X
  431. X    trial = jdate * sec_day; 
  432. X
  433. X    yr -= 1900;
  434. X
  435. X    tp = localtime(&trial);
  436. X
  437. X    if (tp->tm_year != yr) {
  438. X        /*
  439. X        * We may fail this test once a year because of time zone
  440. X         * and daylight savings time errors.  This bounces the
  441. X         * trial time past the boundary.  The error introduced is
  442. X         * corrected below.
  443. X         */
  444. X        trial += sec_day*(yr - tp->tm_year);
  445. X        tp = localtime(&trial);
  446. X    }
  447. X    if (tp->tm_mon != mo) {
  448. X        /* We may fail this test once a month.  */
  449. X        trial += sec_day*(mo - tp->tm_mon);
  450. X        tp = localtime(&trial);
  451. X    }
  452. X    if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec != day) {
  453. X    trial -= (tp->tm_mday - day)*sec_day +  tp->tm_hour*sec_hr
  454. X         + tp->tm_min*sec_min + tp->tm_sec;
  455. X    }
  456. X
  457. X#ifdef DEBUGDTS
  458. X    tp = localtime(&trial);
  459. X    if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec + 
  460. X    tp->tm_year + tp->tm_mon != yr+mo+day)
  461. X        error("Dts broke down");
  462. X#endif
  463. X
  464. X    return ((double)trial);
  465. X}
  466. X
  467. Xdouble
  468. Xdotts(hr, min, sec)
  469. Xint hr, min, sec;
  470. X{
  471. X    if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
  472. X    error ("@tts: Invalid argument");
  473. X    return ((double)0);
  474. X    }
  475. X    return ((double)(sec+min*60+hr*3600));
  476. X}
  477. X
  478. Xdouble
  479. Xdotime(which, when)
  480. Xint which;
  481. Xdouble when;
  482. X{
  483. X    long time();
  484. X
  485. X    static long t_cache;
  486. X    static struct tm tm_cache;
  487. X    struct tm *tp;
  488. X    long tloc;
  489. X
  490. X    if (which == NOW) 
  491. X        return (double)time((long *)0);
  492. X
  493. X    tloc = (long)when;
  494. X
  495. X    if (tloc != t_cache) {
  496. X        tp = localtime(&tloc);
  497. X        tm_cache = *tp;
  498. X        tm_cache.tm_mon += 1;
  499. X        tm_cache.tm_year += 1900;
  500. X        t_cache = tloc;
  501. X    }
  502. X
  503. X    switch (which) {
  504. X        case HOUR: return((double)(tm_cache.tm_hour));
  505. X        case MINUTE: return((double)(tm_cache.tm_min));
  506. X        case SECOND: return((double)(tm_cache.tm_sec));
  507. X        case MONTH: return((double)(tm_cache.tm_mon));
  508. X        case DAY: return((double)(tm_cache.tm_mday));
  509. X        case YEAR: return((double)(tm_cache.tm_year));
  510. X    }
  511. X    /* Safety net */
  512. X    return ((double)0);
  513. X}
  514. X
  515. Xdouble
  516. Xdoston(s)
  517. Xchar *s;
  518. X{
  519. X    char *strtof();
  520. X    double v;
  521. X
  522. X    if (!s)
  523. X    return((double)0);
  524. X
  525. X    (void)strtof(s, &v);
  526. X    xfree(s);
  527. X    return(v);
  528. X}
  529. X
  530. Xdouble
  531. Xdoeqs(s1, s2)
  532. Xchar *s1, *s2;
  533. X{
  534. X    double v;
  535. X
  536. X    if (!s1 && !s2)
  537. X    return((double)1.0);
  538. X
  539. X    if (!s1 || !s2)
  540. X    v = 0.0;
  541. X    else if (strcmp(s1, s2) == 0)
  542. X    v = 1.0;
  543. X    else
  544. X    v = 0.0;
  545. X
  546. X    if (s1)
  547. X        xfree(s1);
  548. X
  549. X    if (s2)
  550. X        xfree(s2);
  551. X
  552. X    return(v);
  553. X}
  554. X
  555. X
  556. X/*
  557. X * Given a string representing a column name and a value which is a column
  558. X * number, return a pointer to the selected cell's entry, if any, else 0.  Use
  559. X * only the integer part of the column number.  Always free the string.
  560. X */
  561. X
  562. Xstruct ent *
  563. Xgetent (colstr, rowdoub)
  564. X    char *colstr;
  565. X    double rowdoub;
  566. X{
  567. X    int collen;        /* length of string */
  568. X    int row, col;    /* integer values   */
  569. X    struct ent *ep = (struct ent *)0;    /* selected entry   */
  570. X
  571. X    if (((row = (int) floor (rowdoub)) >= 0)
  572. X     && (row < maxrows)                /* in range */
  573. X     && ((collen = strlen (colstr)) <= 2)    /* not too long */
  574. X     && ((col = atocol (colstr, collen)) >= 0)
  575. X     && (col < maxcols))            /* in range */
  576. X    {
  577. X    ep = *ATBL(tbl, row, col);
  578. X    }
  579. X
  580. X    xfree (colstr);
  581. X    return (ep);
  582. X}
  583. X
  584. X
  585. X/*
  586. X * Given a string representing a column name and a value which is a column
  587. X * number, return the selected cell's numeric value, if any.
  588. X */
  589. X
  590. Xdouble
  591. Xdonval (colstr, rowdoub)
  592. X    char *colstr;
  593. X    double rowdoub;
  594. X{
  595. X    struct ent *ep;
  596. X
  597. X    return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
  598. X        (ep -> v) : (double)0);
  599. X}
  600. X
  601. X
  602. X/*
  603. X *    The list routines (e.g. dolmax) are called with an LMAX enode.
  604. X *    The left pointer is a chain of ELIST nodes, the right pointer
  605. X *    is a value.
  606. X */
  607. Xdouble
  608. Xdolmax(ep)
  609. Xstruct enode *ep;
  610. X{
  611. X    register int count = 0;
  612. X    register double maxval = 0; /* Assignment to shut up lint */
  613. X    register struct enode *p;
  614. X    register double v;
  615. X
  616. X    for (p = ep; p; p = p->e.o.left) {
  617. X        v = eval(p->e.o.right);
  618. X        if (!count || v > maxval) {
  619. X            maxval = v; count++;
  620. X        }
  621. X    }
  622. X    if (count) return maxval;
  623. X    else return (double)0;
  624. X}
  625. X
  626. Xdouble
  627. Xdolmin(ep)
  628. Xstruct enode *ep;
  629. X{
  630. X    register int count = 0;
  631. X    register double minval = 0; /* Assignment to shut up lint */
  632. X    register struct enode *p;
  633. X    register double v;
  634. X
  635. X    for (p = ep; p; p = p->e.o.left) {
  636. X        v = eval(p->e.o.right);
  637. X        if (!count || v < minval) {
  638. X            minval = v; count++;
  639. X        }
  640. X    }
  641. X    if (count) return minval;
  642. X    else return (double)0;
  643. X}
  644. X
  645. Xdouble 
  646. Xeval(e)
  647. Xregister struct enode *e;
  648. X{
  649. X    if (e == (struct enode *)0) return (double)0;
  650. X    switch (e->op) {
  651. X    case '+':    return (eval(e->e.o.left) + eval(e->e.o.right));
  652. X    case '-':    return (eval(e->e.o.left) - eval(e->e.o.right));
  653. X    case '*':    return (eval(e->e.o.left) * eval(e->e.o.right));
  654. X    case '/':       return (eval(e->e.o.left) / eval(e->e.o.right));
  655. X    case '%':     {    double num, denom;
  656. X            num = floor(eval(e->e.o.left));
  657. X            denom = floor(eval (e->e.o.right));
  658. X            return denom ? num - floor(num/denom)*denom : (double)0; }
  659. X    case '^':    return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
  660. X    case '<':    return (eval(e->e.o.left) < eval(e->e.o.right));
  661. X    case '=':    return (eval(e->e.o.left) == eval(e->e.o.right));
  662. X    case '>':    return (eval(e->e.o.left) > eval(e->e.o.right));
  663. X    case '&':    return (eval(e->e.o.left) && eval(e->e.o.right));
  664. X    case '|':    return (eval(e->e.o.left) || eval(e->e.o.right));
  665. X    case IF:
  666. X    case '?':    return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
  667. X                        : eval(e->e.o.right->e.o.right);
  668. X    case 'm':    return (-eval(e->e.o.right));
  669. X    case 'f':    return (eval(e->e.o.right));
  670. X    case '~':    return (eval(e->e.o.right) == 0.0);
  671. X    case 'k':    return (e->e.k);
  672. X    case 'v':    return (e->e.v.vp->v);
  673. X    case INDEX:
  674. X    case LOOKUP:
  675. X    case HLOOKUP:
  676. X    case VLOOKUP:
  677. X        {    register r,c;
  678. X        register maxr, maxc;
  679. X        register minr, minc;
  680. X        maxr = e->e.o.right->e.r.right.vp -> row;
  681. X        maxc = e->e.o.right->e.r.right.vp -> col;
  682. X        minr = e->e.o.right->e.r.left.vp -> row;
  683. X        minc = e->e.o.right->e.r.left.vp -> col;
  684. X        if (minr>maxr) r = maxr, maxr = minr, minr = r;
  685. X        if (minc>maxc) c = maxc, maxc = minc, minc = c;
  686. X        switch(e->op){
  687. X        case LOOKUP:
  688. X            return dolookup(e->e.o.left, minr, minc, maxr, maxc,
  689. X                     minr==maxr, minc==maxc);
  690. X        case HLOOKUP:
  691. X                return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
  692. X            (int) eval(e->e.o.left->e.o.right), 0);
  693. X        case VLOOKUP:
  694. X                return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
  695. X            0, (int) eval(e->e.o.left->e.o.right));
  696. X        case INDEX:
  697. X            return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
  698. X        }
  699. X        }
  700. X    case REDUCE | '+':
  701. X     case REDUCE | '*':
  702. X     case REDUCE | 'a':
  703. X     case REDUCE | 'c':
  704. X     case REDUCE | 's':
  705. X    case REDUCE | MAX:
  706. X    case REDUCE | MIN:
  707. X        {    register r,c;
  708. X        register maxr, maxc;
  709. X        register minr, minc;
  710. X        maxr = e->e.r.right.vp -> row;
  711. X        maxc = e->e.r.right.vp -> col;
  712. X        minr = e->e.r.left.vp -> row;
  713. X        minc = e->e.r.left.vp -> col;
  714. X        if (minr>maxr) r = maxr, maxr = minr, minr = r;
  715. X        if (minc>maxc) c = maxc, maxc = minc, minc = c;
  716. X            switch (e->op) {
  717. X                case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
  718. X                 case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
  719. X                 case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
  720. X                 case REDUCE | 'c': return docount(minr, minc, maxr, maxc);
  721. X                 case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
  722. X                 case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
  723. X                 case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
  724. X        }
  725. X        }
  726. X    case ABS:     return (fn1_eval( fabs, eval(e->e.o.right)));
  727. X    case ACOS:     return (fn1_eval( acos, eval(e->e.o.right)));
  728. X    case ASIN:     return (fn1_eval( asin, eval(e->e.o.right)));
  729. X    case ATAN:     return (fn1_eval( atan, eval(e->e.o.right)));
  730. X    case ATAN2:     return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
  731. X    case CEIL:     return (fn1_eval( ceil, eval(e->e.o.right)));
  732. X    case COS:     return (fn1_eval( cos, eval(e->e.o.right)));
  733. X    case EXP:     return (fn1_eval( exp, eval(e->e.o.right)));
  734. X    case FABS:     return (fn1_eval( fabs, eval(e->e.o.right)));
  735. X    case FLOOR:     return (fn1_eval( floor, eval(e->e.o.right)));
  736. X    case HYPOT:     return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
  737. X    case LOG:     return (fn1_eval( log, eval(e->e.o.right)));
  738. X    case LOG10:     return (fn1_eval( log10, eval(e->e.o.right)));
  739. X    case POW:     return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
  740. X    case SIN:     return (fn1_eval( sin, eval(e->e.o.right)));
  741. X    case SQRT:     return (fn1_eval( sqrt, eval(e->e.o.right)));
  742. X    case TAN:     return (fn1_eval( tan, eval(e->e.o.right)));
  743. X    case DTR:     return (dtr(eval(e->e.o.right)));
  744. X    case RTD:     return (rtd(eval(e->e.o.right)));
  745. X    case RND:     {
  746. X                double temp;
  747. X                temp = eval(e->e.o.right);
  748. X                return(temp-floor(temp) < 0.5 ?
  749. X                         floor(temp) : ceil(temp));
  750. X            }
  751. X     case ROUND:    {
  752. X                double temp = eval(e->e.o.left);
  753. X                int prec = (int) eval(e->e.o.right), scal = 1;
  754. X                while (prec-- > 0) scal *= 10;
  755. X                temp *= scal;
  756. X                temp = ((temp-floor(temp)) < 0.5 ?
  757. X                    floor(temp) : ceil(temp));
  758. X                return(temp / scal);
  759. X            }
  760. X    case FV:
  761. X    case PV:
  762. X    case PMT:    return(finfunc(e->op,eval(e->e.o.left),
  763. X                   eval(e->e.o.right->e.o.left),
  764. X                      eval(e->e.o.right->e.o.right)));
  765. X    case HOUR:     return (dotime(HOUR, eval(e->e.o.right)));
  766. X    case MINUTE:     return (dotime(MINUTE, eval(e->e.o.right)));
  767. X    case SECOND:     return (dotime(SECOND, eval(e->e.o.right)));
  768. X    case MONTH:     return (dotime(MONTH, eval(e->e.o.right)));
  769. X    case DAY:     return (dotime(DAY, eval(e->e.o.right)));
  770. X    case YEAR:     return (dotime(YEAR, eval(e->e.o.right)));
  771. X    case NOW:     return (dotime(NOW, (double)0.0));
  772. X    case DTS:     return (dodts((int)eval(e->e.o.left),
  773. X                 (int)eval(e->e.o.right->e.o.left),
  774. X                 (int)eval(e->e.o.right->e.o.right)));
  775. X    case TTS:     return (dotts((int)eval(e->e.o.left),
  776. X                 (int)eval(e->e.o.right->e.o.left),
  777. X                 (int)eval(e->e.o.right->e.o.right)));
  778. X    case STON:     return (doston(seval(e->e.o.right)));
  779. X    case EQS:        return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
  780. X    case LMAX:     return dolmax(e);
  781. X    case LMIN:     return dolmin(e);
  782. X    case NVAL:       return (donval(seval(e->e.o.left),eval(e->e.o.right)));
  783. X    default:     error ("Illegal numeric expression");
  784. X             exprerr = 1;
  785. X    }
  786. X    return((double)0.0);
  787. X}
  788. X
  789. X#ifdef SIGVOID
  790. Xvoid
  791. X#endif
  792. Xeval_fpe(signo) /* Trap for FPE errors in eval */
  793. Xint signo;
  794. X{
  795. X#ifdef IEEE_MATH
  796. X    (void)fpsetsticky((fp_except)0);         /* Clear exception */
  797. X#endif /* IEEE_MATH */
  798. X    longjmp(fpe_save, 1);
  799. X}
  800. X
  801. Xdouble fn1_eval(fn, arg)
  802. Xdouble (*fn)();
  803. Xdouble arg;
  804. X{
  805. X    double res;
  806. X    errno = 0;
  807. X    res = (*fn)(arg);
  808. X    if(errno)
  809. X      eval_fpe(0);
  810. X
  811. X    return res;
  812. X}
  813. X
  814. Xdouble fn2_eval(fn, arg1, arg2)
  815. Xdouble (*fn)();
  816. Xdouble arg1, arg2;
  817. X{
  818. X    double res;
  819. X    errno = 0;
  820. X    res = (*fn)(arg1, arg2);
  821. X    if(errno) 
  822. X        eval_fpe(0);
  823. X
  824. X    return res;
  825. X}
  826. X
  827. X/* 
  828. X * Rules for string functions:
  829. X * Take string arguments which they xfree.
  830. X * All returned strings are assumed to be xalloced.
  831. X */
  832. X
  833. Xchar *
  834. Xdocat(s1, s2)
  835. Xregister char *s1, *s2;
  836. X{
  837. X    register char *p;
  838. X    char *arg1, *arg2;
  839. X
  840. X    if (!s1 && !s2)
  841. X    return((char *)0);
  842. X    arg1 = s1 ? s1 : "";
  843. X    arg2 = s2 ? s2 : "";
  844. X    p = xmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
  845. X    (void) strcpy(p, arg1);
  846. X    (void) strcat(p, arg2);
  847. X    if (s1)
  848. X        xfree(s1);
  849. X    if (s2)
  850. X        xfree(s2);
  851. X    return(p);
  852. X}
  853. X
  854. Xchar *
  855. Xdodate(tloc)
  856. Xlong tloc;
  857. X{
  858. X    char *tp;
  859. X    char *p;
  860. X
  861. X    tp = ctime(&tloc);
  862. X    tp[24] = '\0';
  863. X    p = xmalloc((unsigned)25);
  864. X    (void) strcpy(p, tp);
  865. X    return(p);
  866. X}
  867. X
  868. X
  869. Xchar *
  870. Xdofmt(fmtstr, v)
  871. Xchar *fmtstr;
  872. Xdouble v;
  873. X{
  874. X    char buff[FBUFLEN];
  875. X    char *p;
  876. X
  877. X    if (!fmtstr)
  878. X    return((char *)0);
  879. X    (void)sprintf(buff, fmtstr, v);
  880. X    p = xmalloc((unsigned)(strlen(buff)+1));
  881. X    (void) strcpy(p, buff);
  882. X    xfree(fmtstr);
  883. X    return(p);
  884. X}
  885. X
  886. X
  887. X/*
  888. X * Given a command name and a value, run the command with the given value and
  889. X * read and return its first output line (only) as an allocated string, always
  890. X * a copy of prevstr, which is set appropriately first unless external
  891. X * functions are disabled, in which case the previous value is used.  The
  892. X * handling of prevstr and freeing of command is tricky.  Returning an
  893. X * allocated string in all cases, even if null, insures cell expressions are
  894. X * written to files, etc.
  895. X */
  896. X
  897. X#ifdef VMS
  898. Xchar *
  899. Xdoext(command, value)
  900. Xchar *command;
  901. Xdouble value;
  902. X{
  903. X    error("Warning: External functions unavailable on VMS");
  904. X    if (command)
  905. X    xfree(command);
  906. X    return (strcpy (xmalloc((unsigned) 1), "\0"));
  907. X}
  908. X
  909. X#else /* VMS */
  910. X
  911. Xchar *
  912. Xdoext (command, value)
  913. Xchar   *command;
  914. Xdouble value;
  915. X{
  916. X    static char *prevstr = (char *)0;    /* previous result */
  917. X    char buff[FBUFLEN];        /* command line/return, not permanently alloc */
  918. X
  919. X    if (!prevstr) {
  920. X    prevstr = xmalloc((unsigned)1);
  921. X    *prevstr = '\0';
  922. X    }
  923. X    if (!extfunc)    {
  924. X    error ("Warning: external functions disabled; using %s value",
  925. X        prevstr ? "previous" : "null");
  926. X
  927. X    if (command) xfree (command);
  928. X    } else {
  929. X    if (prevstr) xfree (prevstr);        /* no longer needed */
  930. X    prevstr = '\0';
  931. X
  932. X    if ((! command) || (! *command)) {
  933. X        error ("Warning: external function given null command name");
  934. X        if (command) xfree (command);
  935. X    } else {
  936. X        FILE *pp;
  937. X
  938. X        (void) sprintf (buff, "%s %g", command, value); /* build cmd line */
  939. X        xfree (command);
  940. X
  941. X        error ("Running external function...");
  942. X        (void) refresh();
  943. X
  944. X        if ((pp = popen (buff, "r")) == (FILE *) NULL)    /* run it */
  945. X        error ("Warning: running \"%s\" failed", buff);
  946. X        else {
  947. X        if (fgets (buff, sizeof(buff)-1, pp) == NULL)    /* one line */
  948. X            error ("Warning: external function returned nothing");
  949. X        else {
  950. X            char *cp;
  951. X
  952. X            error ("");                /* erase notice */
  953. X            buff[sizeof(buff)-1] = '\0';
  954. X
  955. X            if (cp = strchr (buff, '\n'))    /* contains newline */
  956. X            *cp = '\0';            /* end string there */
  957. X
  958. X            (void) strcpy (prevstr = 
  959. X             xmalloc ((unsigned) (strlen (buff) + 1)), buff);
  960. X             /* save alloc'd copy */
  961. X        }
  962. X        (void) pclose (pp);
  963. X
  964. X        } /* else */
  965. X    } /* else */
  966. X    } /* else */
  967. X    return (strcpy (xmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
  968. X}
  969. X
  970. X#endif /* VMS */
  971. X
  972. X
  973. X/*
  974. X * Given a string representing a column name and a value which is a column
  975. X * number, return the selected cell's string value, if any.  Even if none,
  976. X * still allocate and return a null string so the cell has a label value so
  977. X * the expression is saved in a file, etc.
  978. X */
  979. X
  980. Xchar *
  981. Xdosval (colstr, rowdoub)
  982. X    char *colstr;
  983. X    double rowdoub;
  984. X{
  985. X    struct ent *ep;
  986. X    char *label;
  987. X
  988. X    label = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
  989. X    return (strcpy (xmalloc ((unsigned) (strlen (label) + 1)), label));
  990. X}
  991. X
  992. X
  993. X/*
  994. X * Substring:  Note that v1 and v2 are one-based to users, but zero-based
  995. X * when calling this routine.
  996. X */
  997. X
  998. Xchar *
  999. Xdosubstr(s, v1, v2)
  1000. Xchar *s;
  1001. Xregister int v1,v2;
  1002. X{
  1003. X    register char *s1, *s2;
  1004. X    char *p;
  1005. X
  1006. X    if (!s)
  1007. X    return((char *)0);
  1008. X
  1009. X    if (v2 >= strlen (s))        /* past end */
  1010. X    v2 =  strlen (s) - 1;        /* to end   */
  1011. X
  1012. X    if (v1 < 0 || v1 > v2) {        /* out of range, return null string */
  1013. X    xfree(s);
  1014. X    p = xmalloc((unsigned)1);
  1015. X    p[0] = '\0';
  1016. X    return(p);
  1017. X    }
  1018. X    s2 = p = xmalloc((unsigned)(v2-v1+2));
  1019. X    s1 = &s[v1];
  1020. X    for(; v1 <= v2; s1++, s2++, v1++)
  1021. X    *s2 = *s1;
  1022. X    *s2 = '\0';
  1023. X    xfree(s);
  1024. X    return(p);
  1025. X}
  1026. X
  1027. Xchar *
  1028. Xseval(se)
  1029. Xregister struct enode *se;
  1030. X{
  1031. X    register char *p;
  1032. X
  1033. X    if (se == (struct enode *)0) return (char *)0;
  1034. X    switch (se->op) {
  1035. X    case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
  1036. X             (void) strcpy(p, se->e.s);
  1037. X             return(p);
  1038. X    case O_VAR:    {
  1039. X            struct ent *ep;
  1040. X            ep = se->e.v.vp;
  1041. X
  1042. X            if (!ep->label)
  1043. X                return((char *)0);
  1044. X            p = xmalloc((unsigned)(strlen(ep->label)+1));
  1045. X            (void) strcpy(p, ep->label);
  1046. X            return(p);
  1047. X             }
  1048. X    case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
  1049. X    case 'f':    return(seval(se->e.o.right));
  1050. X    case IF:
  1051. X    case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
  1052. X                         : seval(se->e.o.right->e.o.right));
  1053. X    case DATE:   return(dodate((long)(eval(se->e.o.right))));
  1054. X    case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
  1055. X     case STINDEX:
  1056. X         {    register r,c;
  1057. X         register maxr, maxc;
  1058. X         register minr, minc;
  1059. X         maxr = se->e.o.right->e.r.right.vp -> row;
  1060. X         maxc = se->e.o.right->e.r.right.vp -> col;
  1061. X         minr = se->e.o.right->e.r.left.vp -> row;
  1062. X         minc = se->e.o.right->e.r.left.vp -> col;
  1063. X         if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1064. X         if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1065. X             return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
  1066. X        }
  1067. X    case EXT:    return(doext(seval(se->e.o.left), eval(se->e.o.right)));
  1068. X    case SVAL:   return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
  1069. X    case SUBSTR: return(dosubstr(seval(se->e.o.left),
  1070. X                (int)eval(se->e.o.right->e.o.left) - 1,
  1071. X                (int)eval(se->e.o.right->e.o.right) - 1));
  1072. X    default:
  1073. X             error ("Illegal string expression");
  1074. X             exprerr = 1;
  1075. X             return((char *)0);
  1076. X    }
  1077. X}
  1078. X
  1079. X/*
  1080. X * The graph formed by cell expressions which use other cells's values is not
  1081. X * evaluated "bottom up".  The whole table is merely re-evaluated cell by cell,
  1082. X * top to bottom, left to right, in RealEvalAll().  Each cell's expression uses
  1083. X * constants in other cells.  However, RealEvalAll() notices when a cell gets a
  1084. X * new numeric or string value, and reports if this happens for any cell.
  1085. X * EvalAll() repeats calling RealEvalAll() until there are no changes or the
  1086. X * evaluation count expires.
  1087. X */
  1088. X
  1089. Xint propagation = 10;    /* max number of times to try calculation */
  1090. X
  1091. Xvoid
  1092. Xsetiterations(i)
  1093. Xint i;
  1094. X{
  1095. X    if(i<1) {
  1096. X        error("iteration count must be at least 1");
  1097. X        propagation = 1;
  1098. X        }
  1099. X    else propagation = i;
  1100. X}
  1101. X
  1102. Xvoid
  1103. XEvalAll () {
  1104. X      int lastcnt, repct = 0;
  1105. X  
  1106. X     while ((lastcnt = RealEvalAll()) && (repct++ <= propagation));
  1107. X     if((propagation>1)&& (lastcnt >0 ))
  1108. X         error("Still changing after %d iterations",propagation-1);
  1109. X}
  1110. X
  1111. X/*
  1112. X * Evaluate all cells which have expressions and alter their numeric or string
  1113. X * values.  Return the number of cells which changed.
  1114. X */
  1115. X
  1116. Xint 
  1117. XRealEvalAll () {
  1118. X    register int i,j;
  1119. X    int chgct = 0;
  1120. X    register struct ent *p;
  1121. X
  1122. X    (void) signal(SIGFPE, eval_fpe);
  1123. X#ifdef EXPRTREE
  1124. X    for (p = firstev; p; p = p->evnext)
  1125. X        RealEvalOne(p, &chgct);
  1126. X#else
  1127. X    if(calc_order == BYROWS ) {
  1128. X    for (i=0; i<=maxrow; i++)
  1129. X        for (j=0; j<=maxcol; j++)
  1130. X        if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
  1131. X    }
  1132. X    else if ( calc_order == BYCOLS ) {
  1133. X    for (j=0; j<=maxcol; j++)
  1134. X    {   for (i=0; i<=maxrow; i++)
  1135. X        if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
  1136. X    }
  1137. X    }
  1138. X    else error("Internal error calc_order");
  1139. X#endif
  1140. X    (void) signal(SIGFPE, quit);
  1141. X    return(chgct);
  1142. X}
  1143. X
  1144. Xvoid
  1145. X#ifdef EXPRTREE
  1146. XRealEvalOne(p, chgct)
  1147. Xregister struct ent *p;
  1148. Xint *chgct;
  1149. X#else
  1150. XRealEvalOne(p, i, j, chgct)
  1151. Xregister struct ent *p;
  1152. Xint i, j, *chgct;
  1153. X#endif
  1154. X{
  1155. X    if (p->flags & is_strexpr) {
  1156. X        char *v;
  1157. X        if (setjmp(fpe_save)) {
  1158. X#ifdef EXPRTREE
  1159. X        error("Floating point exception %s", v_name(p->row, p->col));
  1160. X#else
  1161. X        error("Floating point exception %s", v_name(i, j));
  1162. X#endif
  1163. X        v = "";
  1164. X        } else {
  1165. X        v = seval(p->expr);
  1166. X        }
  1167. X        if (!v && !p->label) /* Everything's fine */
  1168. X        return;
  1169. X        if (!p->label || !v || strcmp(v, p->label) != 0) {
  1170. X        (*chgct)++;
  1171. X        p->flags |= is_changed;
  1172. X        changed++;
  1173. X        }
  1174. X        if(p->label)
  1175. X        xfree(p->label);
  1176. X        p->label = v;
  1177. X    } else {
  1178. X        double v;
  1179. X        if (setjmp(fpe_save)) {
  1180. X#ifdef EXPRTREE
  1181. X        error("Floating point exception %s", v_name(p->row, p->col));
  1182. X#else
  1183. X        error("Floating point exception %s", v_name(i, j));
  1184. X#endif
  1185. X        v = (double)0.0;
  1186. X        } else {
  1187. X        v = eval (p->expr);
  1188. X        }
  1189. X        if (v != p->v) {
  1190. X        p->v = v; (*chgct)++;
  1191. X        p->flags |= is_changed|is_valid;
  1192. X        changed++;
  1193. X        }
  1194. X    }
  1195. X}
  1196. X
  1197. Xstruct enode *
  1198. Xnew(op, a1, a2)
  1199. Xint    op;
  1200. Xstruct enode *a1, *a2;
  1201. X{
  1202. X    register struct enode *p;
  1203. X    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1204. X    p->op = op;
  1205. X    p->e.o.left = a1;
  1206. X    p->e.o.right = a2;
  1207. X    return p;
  1208. X}
  1209. X
  1210. Xstruct enode *
  1211. Xnew_var(op, a1)
  1212. Xint    op;
  1213. Xstruct ent_ptr a1;
  1214. X{
  1215. X    register struct enode *p;
  1216. X    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1217. X    p->op = op;
  1218. X    p->e.v = a1;
  1219. X    return p;
  1220. X}
  1221. X
  1222. Xstruct enode *
  1223. Xnew_range(op, a1)
  1224. Xint    op;
  1225. Xstruct range_s a1;
  1226. X{
  1227. X    register struct enode *p;
  1228. X    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1229. X    p->op = op;
  1230. X    p->e.r = a1;
  1231. X    return p;
  1232. X}
  1233. X
  1234. Xstruct enode *
  1235. Xnew_const(op, a1)
  1236. Xint    op;
  1237. Xdouble a1;
  1238. X{
  1239. X    register struct enode *p;
  1240. X    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1241. X    p->op = op;
  1242. X    p->e.k = a1;
  1243. X    return p;
  1244. X}
  1245. X
  1246. Xstruct enode *
  1247. Xnew_str(s)
  1248. Xchar *s;
  1249. X{
  1250. X    register struct enode *p;
  1251. X
  1252. X    p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
  1253. X    p->op = O_SCONST;
  1254. X    p->e.s = s;
  1255. X    return(p);
  1256. X}
  1257. X
  1258. Xvoid
  1259. Xcopy(dv1, dv2, v1, v2)
  1260. Xstruct ent *dv1, *dv2, *v1, *v2;
  1261. X{
  1262. X    int minsr, minsc;
  1263. X    int maxsr, maxsc;
  1264. X    int mindr, mindc;
  1265. X    int maxdr, maxdc;
  1266. X    int vr, vc;
  1267. X    int r, c;
  1268. X
  1269. X    mindr = dv1->row;
  1270. X    mindc = dv1->col;
  1271. X    maxdr = dv2->row;
  1272. X    maxdc = dv2->col;
  1273. X    if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
  1274. X    if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
  1275. X    maxsr = v2->row;
  1276. X    maxsc = v2->col;
  1277. X    minsr = v1->row;
  1278. X    minsc = v1->col;
  1279. X    if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
  1280. X    if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
  1281. X    checkbounds(&maxdr, &maxdc);
  1282. X
  1283. X    erase_area(mindr, mindc, maxdr, maxdc);
  1284. X    if (minsr == maxsr && minsc == maxsc) {
  1285. X    /* Source is a single cell */
  1286. X    for(vr = mindr; vr <= maxdr; vr++)
  1287. X        for (vc = mindc; vc <= maxdc; vc++)
  1288. X        copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
  1289. X    } else if (minsr == maxsr) {
  1290. X    /* Source is a single row */
  1291. X    for (vr = mindr; vr <= maxdr; vr++)
  1292. X        copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
  1293. X    } else if (minsc == maxsc) {
  1294. X    /* Source is a single column */
  1295. X    for (vc = mindc; vc <= maxdc; vc++)
  1296. X        copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
  1297. X    } else {
  1298. X    /* Everything else */
  1299. X    copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
  1300. X    }
  1301. X    sync_refs();
  1302. X}
  1303. X
  1304. Xvoid
  1305. Xcopyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
  1306. Xint vr, vc, minsr, minsc, maxsr, maxsc;
  1307. X{
  1308. X    register struct ent *p;
  1309. X    register struct ent *n;
  1310. X    register int sr, sc;
  1311. X    register int dr, dc;
  1312. X
  1313. X    for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
  1314. X    for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
  1315. X        if (p = *ATBL(tbl, sr, sc))
  1316. X        {    n = lookat (dr, dc);
  1317. X        (void) clearent(n);
  1318. X        copyent( n, p, dr - sr, dc - sc);
  1319. X        }
  1320. X        else
  1321. X        if (n = *ATBL(tbl, dr, dc))
  1322. X        (void) clearent(n);
  1323. X    }
  1324. X}
  1325. X
  1326. Xvoid
  1327. Xeraser(v1, v2)
  1328. Xstruct ent *v1, *v2;
  1329. X{
  1330. X    FullUpdate++;
  1331. X    flush_saved();
  1332. X    erase_area(v1->row, v1->col, v2->row, v2->col);
  1333. X    sync_refs();
  1334. X}
  1335. X
  1336. X/* Goto subroutines */
  1337. X
  1338. Xvoid
  1339. Xg_free()
  1340. X{
  1341. X    switch (gs.g_type) {
  1342. X    case G_STR: xfree(gs.g_s); break;
  1343. X    default: break;
  1344. X    }
  1345. X    gs.g_type = G_NONE;
  1346. X}
  1347. X
  1348. Xvoid
  1349. Xgo_last()
  1350. X{
  1351. X    switch (gs.g_type) {
  1352. X    case G_NONE:
  1353. X        error("Nothing to repeat"); break;
  1354. X    case G_NUM:
  1355. X        num_search(gs.g_n);
  1356. X        break;
  1357. X    case  G_CELL:
  1358. X        moveto(gs.g_row, gs.g_col);
  1359. X            break;
  1360. X    case  G_STR: 
  1361. X        gs.g_type = G_NONE;    /* Don't free the string */
  1362. X               str_search(gs.g_s); 
  1363. X           break;
  1364. X
  1365. X    default: error("go_last: internal error");
  1366. X    }
  1367. X}
  1368. X
  1369. Xvoid
  1370. Xmoveto(row, col)
  1371. Xint row, col;
  1372. X{
  1373. X    currow = row;
  1374. X    curcol = col;
  1375. X    g_free();
  1376. X    gs.g_type = G_CELL;
  1377. X    gs.g_row = currow;
  1378. X    gs.g_col = curcol;
  1379. X}
  1380. X
  1381. Xvoid
  1382. Xnum_search(n)
  1383. Xdouble n;
  1384. X{
  1385. X    register struct ent *p;
  1386. X    register int r,c;
  1387. X    int    endr, endc;
  1388. X
  1389. X    g_free();
  1390. X    gs.g_type = G_NUM;
  1391. X    gs.g_n = n;
  1392. X
  1393. X    if (currow > maxrow)
  1394. X    endr = maxrow ? maxrow-1 : 0;
  1395. X    else
  1396. X    endr = currow;
  1397. X    if (curcol > maxcol)
  1398. X    endc = maxcol ? maxcol-1 : 0;
  1399. X    else
  1400. X    endc = curcol;
  1401. X    r = endr;
  1402. X    c = endc;
  1403. X    do {
  1404. X    if (c < maxcol)
  1405. X        c++;
  1406. X    else {
  1407. X        if (r < maxrow) {
  1408. X        while(++r < maxrow && row_hidden[r]) /* */;
  1409. X        c = 0;
  1410. X        } else {
  1411. X        r = 0;
  1412. X        c = 0;
  1413. X        }
  1414. X    }
  1415. X    if (r == endr && c == endc) {
  1416. X        error("Number not found");
  1417. X        return;
  1418. X    }
  1419. X    p = *ATBL(tbl, r, c);
  1420. X    } while(col_hidden[c] || !p || p && (!(p->flags & is_valid) 
  1421. X                                        || (p->flags&is_valid) && p->v != n));
  1422. X    currow = r;
  1423. X    curcol = c;
  1424. X}
  1425. X
  1426. Xvoid
  1427. Xstr_search(s)
  1428. Xchar *s;
  1429. X{
  1430. X    register struct ent *p;
  1431. X    register int r,c;
  1432. X    int    endr, endc;
  1433. X    char *tmp;
  1434. X
  1435. X#if defined(BSD42) || defined(BSD43)
  1436. X    if ((tmp = re_comp(s)) != (char *)0) {
  1437. X    xfree(s);
  1438. X    error(tmp);
  1439. X    return;
  1440. X    }
  1441. X#endif
  1442. X#if defined(SYSV2) || defined(SYSV3)
  1443. X    if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
  1444. X    xfree(s);
  1445. X    error("Invalid search string");
  1446. X    return;
  1447. X    }
  1448. X#endif
  1449. X    g_free();
  1450. X    gs.g_type = G_STR;
  1451. X    gs.g_s = s;
  1452. X    if (currow > maxrow)
  1453. X    endr = maxrow ? maxrow-1 : 0;
  1454. X    else
  1455. X    endr = currow;
  1456. X    if (curcol > maxcol)
  1457. X    endc = maxcol ? maxcol-1 : 0;
  1458. X    else
  1459. X    endc = curcol;
  1460. X    r = endr;
  1461. X    c = endc;
  1462. X    do {
  1463. X    if (c < maxcol)
  1464. X        c++;
  1465. X    else {
  1466. X        if (r < maxrow) {
  1467. X        while(++r < maxrow && row_hidden[r]) /* */;
  1468. X        c = 0;
  1469. X        } else {
  1470. X        r = 0;
  1471. X        c = 0;
  1472. X        }
  1473. X    }
  1474. X    if (r == endr && c == endc) {
  1475. X        error("String not found");
  1476. X#if defined(SYSV2) || defined(SYSV3)
  1477. X        free(tmp);
  1478. X#endif
  1479. X        return;
  1480. X    }
  1481. X    p = *ATBL(tbl, r, c);
  1482. X    } while(col_hidden[c] || !p || p && (!(p->label) 
  1483. X#if defined(BSD42) || defined(BSD43)
  1484. X                      || (re_exec(p->label) == 0)));
  1485. X#else
  1486. X#if defined(SYSV2) || defined(SYSV3)
  1487. X                                       || (regex(tmp, p->label) == (char *)0)));
  1488. X#else
  1489. X                                       || (strcmp(s, p->label) != 0)));
  1490. X#endif
  1491. X#endif
  1492. X    currow = r;
  1493. X    curcol = c;
  1494. X#if defined(SYSV2) || defined(SYSV3)
  1495. X    free(tmp);
  1496. X#endif
  1497. X}
  1498. X
  1499. Xvoid
  1500. Xfill (v1, v2, start, inc)
  1501. Xstruct ent *v1, *v2;
  1502. Xdouble start, inc;
  1503. X{
  1504. X    register r,c;
  1505. X    register struct ent *n;
  1506. X    int maxr, maxc;
  1507. X    int minr, minc;
  1508. X
  1509. X    maxr = v2->row;
  1510. X    maxc = v2->col;
  1511. X    minr = v1->row;
  1512. X    minc = v1->col;
  1513. X    if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1514. X    if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1515. X    checkbounds(&maxr, &maxc);
  1516. X    if (minr < 0) minr = 0;
  1517. X    if (minr < 0) minr = 0;
  1518. X
  1519. X    FullUpdate++;
  1520. X    if( calc_order == BYROWS ) {
  1521. X    for (r = minr; r<=maxr; r++)
  1522. X    for (c = minc; c<=maxc; c++) {
  1523. X        n = lookat (r, c);
  1524. X        (void) clearent(n);
  1525. X        n->v = start;
  1526. X        start += inc;
  1527. X        n->flags |= (is_changed|is_valid);
  1528. X    }
  1529. X    }
  1530. X    else if ( calc_order == BYCOLS ) {
  1531. X    for (c = minc; c<=maxc; c++)
  1532. X    for (r = minr; r<=maxr; r++) {
  1533. X        n = lookat (r, c);
  1534. X        (void) clearent(n);
  1535. X        n->v = start;
  1536. X        start += inc;
  1537. X        n->flags |= (is_changed|is_valid);
  1538. X    }
  1539. X    }
  1540. X    else error(" Internal error calc_order");
  1541. X    changed++;
  1542. X}
  1543. X
  1544. Xvoid
  1545. Xlet (v, e)
  1546. Xstruct ent *v;
  1547. Xstruct enode *e;
  1548. X{
  1549. X    double val;
  1550. X
  1551. X    exprerr = 0;
  1552. X    (void) signal(SIGFPE, eval_fpe);
  1553. X    if (setjmp(fpe_save)) {
  1554. X    error ("Floating point exception in cell %s", v_name(v->row, v->col));
  1555. X    val = (double)0.0;
  1556. X    } else {
  1557. X    val = eval(e);
  1558. X    }
  1559. X    (void) signal(SIGFPE, quit);
  1560. X    if (exprerr) {
  1561. X    efree((struct ent *)0, e);
  1562. X    return;
  1563. X    }
  1564. X    if (constant(e)) {
  1565. X    if (!loading)
  1566. X        v->v = val * prescale;
  1567. X    else
  1568. X        v->v = val;
  1569. X    if (!(v->flags & is_strexpr)) {
  1570. X            efree(v, v->expr);
  1571. X        v->expr = (struct enode *)0;
  1572. X    }
  1573. X    efree((struct ent *)0, e);
  1574. X        v->flags |= (is_changed|is_valid);
  1575. X        changed++;
  1576. X        modflg++;
  1577. X    return;
  1578. X    }
  1579. X    efree (v, v->expr);
  1580. X    v->expr = e;
  1581. X    v->flags |= (is_changed|is_valid);
  1582. X    v->flags &= ~is_strexpr;
  1583. X
  1584. X#ifdef EXPRTREE
  1585. X    totoptree(v);
  1586. X#endif
  1587. X    changed++;
  1588. X    modflg++;
  1589. X}
  1590. X
  1591. Xvoid
  1592. Xslet (v, se, flushdir)
  1593. Xstruct ent *v;
  1594. Xstruct enode *se;
  1595. Xint flushdir;
  1596. X{
  1597. X    char *p;
  1598. X
  1599. X    exprerr = 0;
  1600. X    (void) signal(SIGFPE, eval_fpe);
  1601. X    if (setjmp(fpe_save)) {
  1602. X    error ("Floating point exception in cell %s", v_name(v->row, v->col));
  1603. X    p = "";
  1604. X    } else {
  1605. X    p = seval(se);
  1606. X    }
  1607. X    (void) signal(SIGFPE, quit);
  1608. X    if (exprerr) {
  1609. X    efree((struct ent *)0, se);
  1610. X    return;
  1611. X    }
  1612. X    if (constant(se)) {
  1613. X    label(v, p, flushdir);
  1614. X    if (p)
  1615. X        xfree(p);
  1616. X    efree((struct ent *)0, se);
  1617. X    if (v->flags & is_strexpr) {
  1618. X            efree (v, v->expr);
  1619. X        v->expr = (struct enode *)0;
  1620. X        v->flags &= ~is_strexpr;
  1621. X    }
  1622. X    return;
  1623. X    }
  1624. X    efree (v, v->expr);
  1625. X    v->expr = se;
  1626. X    v->flags |= (is_changed|is_strexpr);
  1627. X    if (flushdir<0) v->flags |= is_leftflush;
  1628. X    else v->flags &= ~is_leftflush;
  1629. X
  1630. X#ifdef EXPRTREE
  1631. X    totoptree();
  1632. X#endif
  1633. X    FullUpdate++;
  1634. X    changed++;
  1635. X    modflg++;
  1636. X}
  1637. X
  1638. X#ifdef EXPRTREE
  1639. X/*
  1640. X * put an expression in the expression tree, only the top of each branch is
  1641. X * in the firstev list
  1642. X */
  1643. Xtotoptree(v)
  1644. Xstruct    ent *v;
  1645. X{
  1646. X    int    right;
  1647. X    int    left;
  1648. X    if (!v->expr)
  1649. X    return;
  1650. X
  1651. X#ifdef notdef
  1652. X    right = FALSE;
  1653. X    left = FALSE;
  1654. X    switch(v->expr->op)
  1655. X    {
  1656. X        /* no real expression */
  1657. X    case 'v':
  1658. X        if (v->expr->o.v->evnext)
  1659. X            evdel(v->expr->o.v);
  1660. X    case 'k':
  1661. X    case LMAX:
  1662. X    case LMIN:
  1663. X    case NOW:
  1664. X    case O_SCONST:
  1665. X    case O_VAR:
  1666. X    default:
  1667. X        return;
  1668. X
  1669. X        /* left && right */
  1670. X    case '#':
  1671. X    case '%':
  1672. X    case '&':
  1673. X    case '*':
  1674. X    case '+':
  1675. X    case '-':
  1676. X    case '/':
  1677. X    case '<':
  1678. X    case '=':
  1679. X    case '>':
  1680. X    case '?':
  1681. X    case '^':
  1682. X    case '|':
  1683. X    case ATAN2:
  1684. X    case DTS:
  1685. X    case EQS:
  1686. X    case EXT:
  1687. X    case FMT:
  1688. X    case FV:
  1689. X    case HYPOT:
  1690. X    case IF:
  1691. X    case NVAL:
  1692. X    case PMT:
  1693. X    case POW:
  1694. X    case PV:
  1695. X    case REDUCE | '*':
  1696. X    case REDUCE | '+':
  1697. X    case REDUCE | 'a':
  1698. X    case REDUCE | 'c':
  1699. X    case REDUCE | 's':
  1700. X    case REDUCE | MAX:
  1701. X    case REDUCE | MIN:
  1702. X    case ROUND:
  1703. X    case STINDEX:
  1704. X    case SUBSTR:
  1705. X    case SVAL:
  1706. X    case TTS:
  1707. X        left = right = TRUE;
  1708. X        break;
  1709. X        /* right only */
  1710. X    case 'f':
  1711. X    case 'm':
  1712. X    case '~':
  1713. X    case ABS:
  1714. X    case ACOS:
  1715. X    case ASIN:
  1716. X    case ATAN:
  1717. X    case CEIL:
  1718. X    case COS:
  1719. X    case DATE:
  1720. X    case DAY:
  1721. X    case DTR:
  1722. X    case EXP:
  1723. X    case FABS:
  1724. X    case FLOOR:
  1725. X    case HLOOKUP:
  1726. X    case HOUR:
  1727. X    case IF:
  1728. X    case INDEX:
  1729. X    case LOG10:
  1730. X    case LOG:
  1731. X    case LOOKUP:
  1732. X    case MINUTE:
  1733. X    case MONTH:
  1734. X    case RND:
  1735. X    case RTD:
  1736. X    case SECOND:
  1737. X    case SIN:
  1738. X    case SQRT:
  1739. X    case STON:
  1740. X    case TAN:
  1741. X    case VLOOKUP:
  1742. X    case YEAR:
  1743. X        right = TRUE;
  1744. X        break;
  1745. X    }
  1746. X    /* for now insert at the beginning of the list */
  1747. X    v->evnext = firstev;
  1748. X    v->evprev = (struct ent *)0;
  1749. X    if (firstev)
  1750. X    firstev->evprev = v;
  1751. X    firstev = v;
  1752. X#endif
  1753. X    firstev = v;
  1754. X}
  1755. X#endif /* EXPRTREE*/
  1756. X
  1757. Xvoid
  1758. Xhide_row(arg)
  1759. Xint arg;
  1760. X{
  1761. X    if (arg < 0) {
  1762. X    error("Invalid Range");
  1763. X    return;
  1764. X    }
  1765. X    if (arg >= maxrows-1)
  1766. X    {
  1767. X    if (!growtbl(GROWROW, arg+1, 0))
  1768. X    {    error("You can't hide the last row");
  1769. X        return;
  1770. X    }
  1771. X    }
  1772. X    FullUpdate++;
  1773. X    row_hidden[arg] = 1;
  1774. X}
  1775. X
  1776. Xvoid
  1777. Xhide_col(arg)
  1778. Xint arg;
  1779. X{
  1780. X    if (arg < 0) {
  1781. X    error("Invalid Range");
  1782. X    return;
  1783. X    }
  1784. X    if (arg >= maxcols-1)
  1785. X    {    if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
  1786. X    {    error("You can't hide the last col");
  1787. X        return;
  1788. X    }
  1789. X    }
  1790. X    FullUpdate++;
  1791. X    col_hidden[arg] = 1;
  1792. X}
  1793. X
  1794. Xvoid
  1795. Xclearent (v)
  1796. Xstruct ent *v;
  1797. X{
  1798. X    if (!v)
  1799. X    return;
  1800. X    label(v,"",-1);
  1801. X    v->v = (double)0;
  1802. X    if (v->expr)
  1803. X    efree(v, v->expr);
  1804. X    v->expr = (struct enode *)0;
  1805. X    v->flags |= (is_changed);
  1806. X    v->flags &= ~(is_valid);
  1807. X    changed++;
  1808. X    modflg++;
  1809. X}
  1810. X
  1811. X/*
  1812. X * Say if an expression is a constant (return 1) or not.
  1813. X */
  1814. Xint
  1815. Xconstant (e)
  1816. X    register struct enode *e;
  1817. X{
  1818. X    return ((e == (struct enode *)0)
  1819. X     || ((e -> op) == O_CONST)
  1820. X     || ((e -> op) == O_SCONST)
  1821. X     || (((e -> op) != O_VAR)
  1822. X      && (((e -> op) & REDUCE) != REDUCE)
  1823. X      && constant (e -> e.o.left)
  1824. X      && constant (e -> e.o.right)
  1825. X      && (e -> op != EXT)     /* functions look like constants but aren't */
  1826. X      && (e -> op != NVAL)
  1827. X      && (e -> op != SVAL)
  1828. X      && (e -> op != NOW)));
  1829. X}
  1830. X
  1831. Xvoid
  1832. Xefree (v, e)
  1833. Xstruct ent *v;
  1834. Xstruct enode *e;
  1835. X{
  1836. X    if (e) {
  1837. X    if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
  1838. X        && (e->op & REDUCE) != REDUCE) {
  1839. X        efree(v, e->e.o.left);
  1840. X        efree(v, e->e.o.right);
  1841. X    }
  1842. X    if (e->op == O_SCONST && e->e.s)
  1843. X        xfree(e->e.s);
  1844. X    xfree ((char *)e);
  1845. X
  1846. X#ifdef EXPRTREE
  1847. X    /* delete this cell from the eval list */
  1848. X    if (v)
  1849. X    {    if (v->evprev)
  1850. X            v->evprev->evnext = v->evnext;
  1851. X        if (v->evnext)
  1852. X            v->evnext->evprev = v->evprev;
  1853. X    }
  1854. X#endif /* EXPRTREE */
  1855. X    }
  1856. X}
  1857. X
  1858. Xvoid
  1859. Xlabel (v, s, flushdir)
  1860. Xregister struct ent *v;
  1861. Xregister char *s;
  1862. Xint    flushdir;
  1863. X{
  1864. X    if (v) {
  1865. X    if (flushdir==0 && v->flags&is_valid) {
  1866. X        register struct ent *tv;
  1867. X        if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
  1868. X        v = tv, flushdir = 1;
  1869. X        else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
  1870. X        v = tv, flushdir = -1;
  1871. X        else flushdir = -1;
  1872. X    }
  1873. X    if (v->label) xfree((char *)(v->label));
  1874. X    if (s && s[0]) {
  1875. X        v->label = xmalloc ((unsigned)(strlen(s)+1));
  1876. X        (void) strcpy (v->label, s);
  1877. X    } else
  1878. X        v->label = (char *)0;
  1879. X    if (flushdir<0) v->flags |= is_leftflush;
  1880. X    else v->flags &= ~is_leftflush;
  1881. X    FullUpdate++;
  1882. X    modflg++;
  1883. X    }
  1884. X}
  1885. X
  1886. Xvoid
  1887. Xdecodev (v)
  1888. Xstruct ent_ptr v; 
  1889. X{
  1890. X    register struct range *r;
  1891. X
  1892. X    if (!v.vp) (void)sprintf (line+linelim,"VAR?");
  1893. X    else if ((r = find_range((char *)0, 0, v.vp, v.vp)) && !r->r_is_range)
  1894. X        (void)sprintf(line+linelim, "%s", r->r_name);
  1895. X    else
  1896. X        (void)sprintf (line+linelim, "%s%s%s%d",
  1897. X            v.vf & FIX_COL ? "$" : "",
  1898. X            coltoa(v.vp->col),
  1899. X            v.vf & FIX_ROW ? "$" : "",
  1900. X            v.vp->row);
  1901. X    linelim += strlen (line+linelim);
  1902. X}
  1903. X
  1904. Xchar *
  1905. Xcoltoa(col)
  1906. Xint col;
  1907. X{
  1908. X    static char rname[3];
  1909. X    register char *p = rname;
  1910. X
  1911. X    if (col > 25) {
  1912. X    *p++ = col/26 + 'A' - 1;
  1913. X    col %= 26;
  1914. X    }
  1915. X    *p++ = col+'A';
  1916. X    *p = '\0';
  1917. X    return(rname);
  1918. X}
  1919. X
  1920. X/*
  1921. X *    To make list elements come out in the same order
  1922. X *    they were entered, we must do a depth-first eval
  1923. X *    of the ELIST tree
  1924. X */
  1925. Xstatic void
  1926. Xdecompile_list(p)
  1927. Xstruct enode *p;
  1928. X{
  1929. X    if (!p) return;
  1930. X    decompile_list(p->e.o.left);    /* depth first */
  1931. X        decompile(p->e.o.right, 0);
  1932. X    line[linelim++] = ',';
  1933. X}
  1934. X
  1935. Xvoid
  1936. Xdecompile(e, priority)
  1937. Xregister struct enode *e;
  1938. Xint    priority;
  1939. X{
  1940. X    register char *s;
  1941. X    if (e) {
  1942. X    int mypriority;
  1943. X    switch (e->op) {
  1944. X    default: mypriority = 99; break;
  1945. X    case '?': mypriority = 1; break;
  1946. X    case ':': mypriority = 2; break;
  1947. X    case '|': mypriority = 3; break;
  1948. X    case '&': mypriority = 4; break;
  1949. X    case '<': case '=': case '>': mypriority = 6; break;
  1950. X    case '+': case '-': case '#': mypriority = 8; break;
  1951. X    case '*': case '/': case '%': mypriority = 10; break;
  1952. X    case '^': mypriority = 12; break;
  1953. X    }
  1954. X    if (mypriority<priority) line[linelim++] = '(';
  1955. X    switch (e->op) {
  1956. X    case 'f':    for (s="fixed "; line[linelim++] = *s++;);
  1957. X            linelim--;
  1958. X            decompile (e->e.o.right, 30);
  1959. X            break;
  1960. X    case 'm':    line[linelim++] = '-';
  1961. X            decompile (e->e.o.right, 30);
  1962. X            break;
  1963. X    case '~':    line[linelim++] = '~';
  1964. X            decompile (e->e.o.right, 30);
  1965. X            break;
  1966. X    case 'v':    decodev (e->e.v);
  1967. X            break;
  1968. X    case 'k':    (void)sprintf (line+linelim,"%.15g",e->e.k);
  1969. X            linelim += strlen (line+linelim);
  1970. X            break;
  1971. X    case '$':    (void)sprintf (line+linelim, "\"%s\"", e->e.s);
  1972. X            linelim += strlen(line+linelim);
  1973. X            break;
  1974. X
  1975. X    case REDUCE | '+': range_arg( "@sum(", e); break;
  1976. X    case REDUCE | '*': range_arg( "@prod(", e); break;
  1977. X    case REDUCE | 'a': range_arg( "@avg(", e); break;
  1978. X    case REDUCE | 'c': range_arg( "@count(", e); break;
  1979. X    case REDUCE | 's': range_arg( "@stddev(", e); break;
  1980. X    case REDUCE | MAX: range_arg( "@max(", e); break;
  1981. X    case REDUCE | MIN: range_arg( "@min(", e); break;
  1982. X
  1983. X    case ABS:        one_arg( "@abs(", e); break;
  1984. X    case ACOS:    one_arg( "@acos(", e); break;
  1985. X    case ASIN:    one_arg( "@asin(", e); break;
  1986. X    case ATAN:    one_arg( "@atan(", e); break;
  1987. X    case ATAN2:    two_arg( "@atan2(", e); break;
  1988. X    case CEIL:    one_arg( "@ceil(", e); break;
  1989. X    case COS:    one_arg( "@cos(", e); break;
  1990. X    case EXP:    one_arg( "@exp(", e); break;
  1991. X    case FABS:    one_arg( "@fabs(", e); break;
  1992. X    case FLOOR:    one_arg( "@floor(", e); break;
  1993. X    case HYPOT:    two_arg( "@hypot(", e); break;
  1994. X    case LOG:    one_arg( "@ln(", e); break;
  1995. X    case LOG10:    one_arg( "@log(", e); break;
  1996. X    case POW:    two_arg( "@pow(", e); break;
  1997. X    case SIN:    one_arg( "@sin(", e); break;
  1998. X    case SQRT:    one_arg( "@sqrt(", e); break;
  1999. X    case TAN:    one_arg( "@tan(", e); break;
  2000. X    case DTR:    one_arg( "@dtr(", e); break;
  2001. X    case RTD:    one_arg( "@rtd(", e); break;
  2002. X    case RND:    one_arg( "@rnd(", e); break;
  2003. X    case ROUND:    two_arg( "@round(", e); break;
  2004. X    case HOUR:    one_arg( "@hour(", e); break;
  2005. X    case MINUTE:    one_arg( "@minute(", e); break;
  2006. X    case SECOND:    one_arg( "@second(", e); break;
  2007. X    case MONTH:    one_arg( "@month(", e); break;
  2008. X    case DAY:    one_arg( "@day(", e); break;
  2009. X    case YEAR:    one_arg( "@year(", e); break;
  2010. X    case DATE:    one_arg( "@date(", e); break;
  2011. X    case DTS:    three_arg( "@dts(", e); break;
  2012. X    case TTS:    three_arg( "@tts(", e); break;
  2013. X    case STON:    one_arg( "@ston(", e); break;
  2014. X    case FMT:    two_arg( "@fmt(", e); break;
  2015. X    case EQS:    two_arg( "@eqs(", e); break;
  2016. X    case NOW:    for ( s = "@now"; line[linelim++] = *s++;);
  2017. X            linelim--;
  2018. X            break;
  2019. X    case LMAX:    list_arg("@max(", e); break;
  2020. X    case LMIN:     list_arg("@min(", e); break;
  2021. X    case FV:    three_arg("@fv(", e); break;
  2022. X    case PV:    three_arg("@pv(", e); break;
  2023. X    case PMT:    three_arg("@pmt(", e); break;
  2024. X    case NVAL:    two_arg("@nval(", e); break;
  2025. X    case SVAL:    two_arg("@sval(", e); break;
  2026. X    case EXT:    two_arg("@ext(", e); break;
  2027. X    case SUBSTR:    three_arg("@substr(", e); break;
  2028. X    case STINDEX:    index_arg("@stindex(", e); break;
  2029. X    case INDEX:    index_arg("@index(", e); break;
  2030. X    case LOOKUP:    index_arg("@lookup(", e); break;
  2031. X    case HLOOKUP:    two_arg_index("@hlookup(", e); break;
  2032. X    case VLOOKUP:    two_arg_index("@vlookup(", e); break;
  2033. X    case IF:    three_arg("@if(", e); break;
  2034. X    default:    decompile (e->e.o.left, mypriority);
  2035. X            line[linelim++] = e->op;
  2036. X            decompile (e->e.o.right, mypriority+1);
  2037. X            break;
  2038. X    }
  2039. X    if (mypriority<priority) line[linelim++] = ')';
  2040. X    } else line[linelim++] = '?';
  2041. X}
  2042. X
  2043. Xvoid
  2044. Xindex_arg(s, e)
  2045. Xchar *s;
  2046. Xstruct enode *e;
  2047. X{
  2048. X    for (; line[linelim++] = *s++;);
  2049. X    linelim--;
  2050. X    decompile( e-> e.o.left, 0 );
  2051. X    range_arg(", ", e->e.o.right);
  2052. X}
  2053. X
  2054. Xvoid
  2055. Xtwo_arg_index(s, e)
  2056. Xchar *s;
  2057. Xstruct enode *e;
  2058. X{
  2059. X    for (; line[linelim++] = *s++;);
  2060. X    linelim--;
  2061. X    decompile( e->e.o.left->e.o.left, 0 );
  2062. X    range_arg(",", e->e.o.right);
  2063. X    linelim--;
  2064. X    line[linelim++] = ',';
  2065. X    decompile( e->e.o.left->e.o.right, 0 );
  2066. X    line[linelim++] = ')';
  2067. X}
  2068. X
  2069. Xvoid
  2070. Xlist_arg(s, e)
  2071. Xchar *s;
  2072. Xstruct enode *e;
  2073. X{
  2074. X    for (; line[linelim++] = *s++;);
  2075. X    linelim--;
  2076. X
  2077. X    decompile (e->e.o.right, 0);
  2078. X    line[linelim++] = ',';
  2079. X    decompile_list(e->e.o.left);
  2080. X    line[linelim - 1] = ')';
  2081. X}
  2082. X
  2083. Xvoid
  2084. Xone_arg(s, e)
  2085. Xchar *s;
  2086. Xstruct enode *e;
  2087. X{
  2088. X    for (; line[linelim++] = *s++;);
  2089. X    linelim--;
  2090. X    decompile (e->e.o.right, 0);
  2091. X    line[linelim++] = ')';
  2092. X}
  2093. X
  2094. Xvoid
  2095. Xtwo_arg(s,e)
  2096. Xchar *s;
  2097. Xstruct enode *e;
  2098. X{
  2099. X    for (; line[linelim++] = *s++;);
  2100. X    linelim--;
  2101. X    decompile (e->e.o.left, 0);
  2102. X    line[linelim++] = ',';
  2103. X    decompile (e->e.o.right, 0);
  2104. X    line[linelim++] = ')';
  2105. X}
  2106. X
  2107. Xvoid
  2108. Xthree_arg(s,e)
  2109. Xchar *s;
  2110. Xstruct enode *e;
  2111. X{
  2112. X    for (; line[linelim++] = *s++;);
  2113. X    linelim--;
  2114. X    decompile (e->e.o.left, 0);
  2115. X    line[linelim++] = ',';
  2116. X    decompile (e->e.o.right->e.o.left, 0);
  2117. X    line[linelim++] = ',';
  2118. X    decompile (e->e.o.right->e.o.right, 0);
  2119. X    line[linelim++] = ')';
  2120. X}
  2121. X
  2122. Xvoid
  2123. Xrange_arg(s,e)
  2124. Xchar *s;
  2125. Xstruct enode *e;
  2126. X{
  2127. X    struct range *r;
  2128. X
  2129. X    for (; line[linelim++] = *s++;);
  2130. X    linelim--;
  2131. X    if ((r = find_range((char *)0, 0, e->e.r.left.vp,
  2132. X                 e->e.r.right.vp)) && r->r_is_range) {
  2133. X    (void)sprintf(line+linelim, "%s", r->r_name);
  2134. X    linelim += strlen(line+linelim);
  2135. X    } else {
  2136. X    decodev (e->e.r.left);
  2137. X    line[linelim++] = ':';
  2138. X    decodev (e->e.r.right);
  2139. X    }
  2140. X    line[linelim++] = ')';
  2141. X}
  2142. X
  2143. Xvoid
  2144. Xeditv (row, col)
  2145. Xint row, col;
  2146. X{
  2147. X    register struct ent *p;
  2148. X
  2149. X    p = lookat (row, col);
  2150. X    (void)sprintf (line, "let %s = ", v_name(row, col));
  2151. X    linelim = strlen(line);
  2152. X    if (p->flags & is_strexpr || p->expr == 0) {
  2153. X    (void)sprintf (line+linelim, "%.15g", p->v);
  2154. X    linelim += strlen (line+linelim);
  2155. X    } else {
  2156. X        editexp(row,col);
  2157. X    }
  2158. X}
  2159. X
  2160. Xvoid
  2161. Xeditexp(row,col)
  2162. Xint row, col;
  2163. X{
  2164. X    register struct ent *p;
  2165. X
  2166. X    p = lookat (row, col);
  2167. X    decompile (p->expr, 0);
  2168. X    line[linelim] = '\0';
  2169. X}
  2170. X
  2171. Xvoid
  2172. Xedits (row, col)
  2173. Xint row, col;
  2174. X{
  2175. X    register struct ent *p;
  2176. X
  2177. X    p = lookat (row, col);
  2178. X    (void)sprintf (line, "%sstring %s = ",
  2179. X            ((p->flags&is_leftflush) ? "left" : "right"),
  2180. X            v_name(row, col));
  2181. X    linelim = strlen(line);
  2182. X    if (p->flags & is_strexpr && p->expr) {
  2183. X    editexp(row, col);
  2184. X    } else if (p->label) {
  2185. X        (void)sprintf (line+linelim, "\"%s\"", p->label);
  2186. X        linelim += strlen (line+linelim);
  2187. X    } else {
  2188. X        (void)sprintf (line+linelim, "\"");
  2189. X        linelim += 1;
  2190. X    }
  2191. X}
  2192. END_OF_FILE
  2193.   if test 48096 -ne `wc -c <'interp.c'`; then
  2194.     echo shar: \"'interp.c'\" unpacked with wrong size!
  2195.   fi
  2196.   # end of 'interp.c'
  2197. fi
  2198. if test -f 'sc6.8p1.hdr' -a "${1}" != "-c" ; then 
  2199.   echo shar: Will not clobber existing file \"'sc6.8p1.hdr'\"
  2200. else
  2201.   echo shar: Extracting \"'sc6.8p1.hdr'\" \(2645 characters\)
  2202.   sed "s/^X//" >'sc6.8p1.hdr' <<'END_OF_FILE'
  2203. XFrom @uunet.uu.net:sawmill!buhrt@newton.physics.purdue.edu Thu Jun 21 22:27:39 1990
  2204. XReceived: from BBN.COM by pineapple.bbn.com id <AA17042@pineapple.bbn.com>; Thu, 21 Jun 90 22:26:50 -0400
  2205. XReceived: from uunet.UU.NET by BBN.COM id ab13765; 21 Jun 90 22:25 EDT
  2206. XReceived: from newton.physics.purdue.edu by uunet.uu.net (5.61/1.14) with UUCP 
  2207. X    id AA09100; Thu, 21 Jun 90 22:24:58 -0400
  2208. XReceived: from pur-ee.UUCP by rutgers.edu (5.59/SMI4.0/RU1.3/3.06) with UUCP 
  2209. X    id AA09408; Thu, 21 Jun 90 20:35:48 EDT
  2210. XReceived: from newton.physics.purdue.edu by ee.ecn.purdue.edu (5.61/1.22jrs)
  2211. X    id AA12057; Thu, 21 Jun 90 16:05:59 -0500
  2212. XReceived: from sawmill.UUCP by newton.physics.purdue.edu (5.61/1.34)
  2213. X    id AA01613; Thu, 21 Jun 90 16:00:19 -0500
  2214. XReceived: by sawmill.UUCP (5.61/1.35)
  2215. X    id AA08015; Thu, 21 Jun 90 15:36:01 -0500
  2216. XDate: Thu, 21 Jun 90 15:36:01 -0500
  2217. XFrom: Jeffery A Buhrt <sawmill!buhrt@newton.physics.purdue.edu>
  2218. XMessage-Id: <9006212036.AA08015@sawmill.UUCP>
  2219. XTo: uunet!sources@uunet.uu.net
  2220. XSubject: Sc6.8 (part 1 of 4)
  2221. XStatus: R
  2222. X
  2223. X
  2224. XRobert Bond (sequent!rgb) has turned Sc's maintenance over to me.
  2225. X
  2226. Xsh (unshar) all four parts.
  2227. XEdit Makefile
  2228. Xmake sc psc
  2229. X
  2230. XIf you have /etc/magic (for 'file' (or 'att file')) add:
  2231. X38    string        Spreadsheet    sc file
  2232. XThank you: edgard@cao.gipsi.fr
  2233. X
  2234. XTested on a Sequent Symmetry (gcc, cc, atscc), 3b2/400 (cc, fpcc),
  2235. X    3b1 (3.51m-cc,gcc), '386 (AT&T3.2.2-cc,gcc), '286 (Microport 2.4-cc),
  2236. X
  2237. XPlease send any diffs/changes/comments you might make/have
  2238. X(make sure to include enough context diffs to help in patching, and please
  2239. Xnote the version number the patch is w/r to).
  2240. X
  2241. XFor all testers: 6.8 is the same as 6.7.1.3
  2242. X
  2243. X                        -Jeff Buhrt
  2244. X                        Grauel Enterprises, Inc.
  2245. X                        317-477-6000
  2246. X    {newton.physics.purdue.edu (aka: pur-phy), sequent}!sawmill!buhrt
  2247. X
  2248. XCHANGES BETWEEN 6.1 and 6.8
  2249. X
  2250. XDave Lewis - 
  2251. X    Found and fixed a null pointer dereference in the 'R' command.
  2252. X
  2253. XRob McMahon -
  2254. X    Changed the ctl() macro to work with ANSI style compilers.
  2255. X    Cleaned up some non-readonly text problems.
  2256. X
  2257. XRick Linck -
  2258. X    Fixed a bug in lex.c - Ann Arbor Ambassadors have long ks and ke
  2259. X    termcap entries.
  2260. X
  2261. XSam Drake -
  2262. X    A fix for undefined C_* symbols in AIX.
  2263. X
  2264. XPeter Brower -
  2265. X    Cleaned up the INTERNATIONAL ifdefs with more portable code.
  2266. X
  2267. XGlen Ditchfield
  2268. X    Cleaned up a problem in crypt.c when the encrypted file shrank.
  2269. X
  2270. XBob Bond -
  2271. X    Vi style editing for the command line.
  2272. X    A bug in range name aliases.
  2273. X
  2274. XJeff Buhrt -
  2275. X    -Added "~" filename expansion.
  2276. X    -702 columns (A-ZZ) and unlimited rows/cells based on max. memory
  2277. X    -fixed a few bugs
  2278. X    -slightly decreased CPU usage
  2279. X    -MAKES backup copies of files (by default: path/#name~)
  2280. X    -understands ~$HOME stuff
  2281. END_OF_FILE
  2282.   if test 2645 -ne `wc -c <'sc6.8p1.hdr'`; then
  2283.     echo shar: \"'sc6.8p1.hdr'\" unpacked with wrong size!
  2284.   fi
  2285.   # end of 'sc6.8p1.hdr'
  2286. fi
  2287. if test -f 'sres.sed' -a "${1}" != "-c" ; then 
  2288.   echo shar: Will not clobber existing file \"'sres.sed'\"
  2289. else
  2290.   echo shar: Extracting \"'sres.sed'\" \(50 characters\)
  2291.   sed "s/^X//" >'sres.sed' <<'END_OF_FILE'
  2292. X/%token.*S_/!d
  2293. X/%token.*S_\(.*\)/s//    "\1",    S_\1,/
  2294. END_OF_FILE
  2295.   if test 50 -ne `wc -c <'sres.sed'`; then
  2296.     echo shar: \"'sres.sed'\" unpacked with wrong size!
  2297.   fi
  2298.   # end of 'sres.sed'
  2299. fi
  2300. echo shar: End of archive 2 \(of 6\).
  2301. cp /dev/null ark2isdone
  2302. MISSING=""
  2303. for I in 1 2 3 4 5 6 ; do
  2304.     if test ! -f ark${I}isdone ; then
  2305.     MISSING="${MISSING} ${I}"
  2306.     fi
  2307. done
  2308. if test "${MISSING}" = "" ; then
  2309.     echo You have unpacked all 6 archives.
  2310.     rm -f ark[1-9]isdone
  2311. else
  2312.     echo You still must unpack the following archives:
  2313.     echo "        " ${MISSING}
  2314. fi
  2315. exit 0
  2316. exit 0 # Just in case...
  2317.